using System;
using System.Collections.Generic;
using System.Text;
using CLELCore.Assembly.StreamTables;
using CLELCore.Assembly.StreamTables.StreamTableRows;
using CLELCore.Assembly.Descriptors;
using CLELCore.Assembly.Descriptors.ClassDescriptors;
using CLELCore.Assembly.BlobStreams;
using CLELCore.Assembly.BlobStreams.BlobInfo;
using CLELCore.Assembly.CLELInstructions;
using CLELCore.Assembly.MethodHeaderDataSections;
using CLELCore.Assembly.MethodHeaderDataSections.MethodHeaderDataSectionRows;
using CLELCore.Assembly.Debug;
using CLELCore.Executable;

namespace CLELCore.Assembly
{
	public class CLELAssembly : CLELExecutable
	{
		private AssemblyTextSection _text;

		//TODO: Set where all new ClassDescriptors are made (like in GetAllClassDescriptors()
		//Also call when update is needed
		private event EventHandler _typedef_update_tokens;

		public AssemblyTextSection TextSection
		{
			get
			{
				return _text;
			}
			set
			{
				_text = value;
			}
		}

		public CLELAssembly(ICLELParser parser)
		{
			parser.Parse(this);
		}
		
		public void Write(ICLELGenerator generator)
		{
			generator.Write(this);
		}

		//Helper Methods
		private MethodHeader GetMethodHeader(Token token)
		{
			if(token != null)
			{
				if(token.Table == StreamTable.METHODDEF_TABLE)
				{
					List<MethodHeader> method_headers = _text.MethodHeaders;
					if(method_headers != null)
					{
						int row = token.Row-1;
						if(row >= 0 && row < method_headers.Count)
						{
							return method_headers[row];
						}
					}
				}
			}
			return null;
		}

		private SectionHeader GetSectionHeader(String sh_name)
		{
			int i;
			for(i = 0;i < _sectionheaders.Length;i++)
			{
				if(_sectionheaders[i].NameAsString.Equals(sh_name))
					return _sectionheaders[i];
			}
			return null;
		}

		private MethodLocalsBlobInfo GetMethodsLocals(Blob b)
		{
			byte [] blob = b.BlobValue;
			return new MethodLocalsBlobInfo(blob,this);
		}

		private Blob GetBlobFromHeap(int offset)
		{
			BlobStream blob_stream = _text.BlobStream;
			return blob_stream.Get(offset);
		}
	
		//offset is RVA
		private void MoveTextSections(int offset,int diff)
		{
			if(diff != 0)
			{
				int i;
				//resize .text section
				SectionHeader text = GetSectionHeader(SectionHeader.TEXT_NAME);
				int text_size = text.VirtualSize;
				text_size += diff;
				text.VirtualSize = text_size;
				//if text section is too large, resize it and move 
				//reset of section headers
				if(text_size > text.SizeOfRawData)
				{
					int align = _ntspecific.FileAlignment;
					int add_align = 0;
					while(text_size > text.SizeOfRawData)
					{
						text.SizeOfRawData = align+text.SizeOfRawData;
						add_align += align;
					}
					//move .rsrc and .reloc section
					SectionHeader sh;
					for(i = 0;i < _sectionheaders.Length;i++)
					{
						sh = _sectionheaders[i];	
						if(sh.VirtualAddress > text.VirtualAddress)
							sh.PointerToRawData = add_align+sh.PointerToRawData;
					}
				}
				//move method headers
				MethodDefTable md = (MethodDefTable)_text.PoundTildaStream.Tables[StreamTable.METHODDEF_TABLE];
				MethodDefTableRow mdr;
				int rva;
				for(i = 0;i < md.Count;i++)
				{
					mdr = md.Get(i);
					rva = mdr.RVA;
					if(offset < rva)
						mdr.RVA = rva+diff;
				}

				//move field default values
				FieldRVATable frva = (FieldRVATable)_text.PoundTildaStream.Tables[StreamTable.FIELDRVA_TABLE];
				if(frva != null)
				{
					FieldRVATableRow fra;
					for(i = 0;i < frva.Count;i++)
					{
						fra = frva.Get(i);
						rva = fra.RVA;
						if(offset < rva)
							fra.RVA = rva+diff;
					}
				}
				
				//List<MethodHeader> headers = _text.MethodHeaders;
				//for(i = 0;i < headers.Count;i++)
				//	if(offset < headers[i].RVA)
				//		headers[i].RVA = headers[i].RVA+diff;
			
				DataDirectories dd = _datadirectories;

				//move metadataroot and metadataroot stream headers
				int off = _text.CLIHeader.Metadata.VirtualAddress;
				if(offset < off)
					_text.CLIHeader.Metadata.VirtualAddress = off+diff;

				off = _text.CLIHeader.Resources.VirtualAddress;
				if(offset < off)
					_text.CLIHeader.Resources.VirtualAddress = off+diff;

				//move Import Address Table
				off = dd[DataDirectories.IMPORTADDRESSTABLE_INDEX].VirtualAddress;
				if(offset < off)
					dd[DataDirectories.IMPORTADDRESSTABLE_INDEX] = new DataDirectory(
						off+diff,dd[DataDirectories.IMPORTADDRESSTABLE_INDEX].Size);
				
				//move CLI Header
				off = dd[DataDirectories.CLIHEADER_INDEX].VirtualAddress;
				if(offset < off)
					dd[DataDirectories.CLIHEADER_INDEX] = new DataDirectory(
						off+diff,dd[DataDirectories.CLIHEADER_INDEX].Size);
			
				//move Import Table
				off = dd[DataDirectories.IMPORTTABLE_INDEX].VirtualAddress;
				if(offset < off)
					dd[DataDirectories.IMPORTTABLE_INDEX] = new DataDirectory(
						off+diff,dd[DataDirectories.IMPORTTABLE_INDEX].Size);
			
				//move Debug table
				off = dd[DataDirectories.DEBUG_INDEX].VirtualAddress;
				if(offset < off)
				{
					dd[DataDirectories.DEBUG_INDEX] = new DataDirectory(
						off+diff,dd[DataDirectories.DEBUG_INDEX].Size);
			
					DebugDirectory debug = _text.DebugDirectory;
					debug.AddressOfRawData += diff;
					debug.PointerToRawData += diff;
				}
			
				//TODO: move Resource table  .rsrc
				//off = dd[DataDirectories.RESOURCETABLE_INDEX].VirtualAddress;
				//if(offset < off)
				//	dd[DataDirectories.RESOURCETABLE_INDEX] = new DataDirectory(
				//		off+diff,dd[DataDirectories.RESOURCETABLE_INDEX].Size);

				if(_text.ImportTable != null)
				{
					int ilt = _text.ImportTable.ImportLookupTable;
					if(offset < ilt)
						_text.ImportTable.ImportLookupTable = ilt+diff;
					int iat = _text.ImportTable.ImportAddressTable;
					if(offset < iat)
						_text.ImportTable.ImportAddressTable = iat+diff;
					int name = _text.ImportTable.Name;
					if(offset < name)
						_text.ImportTable.Name = name+diff;
				}

				if(_text.ImportAddressTable != null)
				{
					int name_table = _text.ImportAddressTable.NameTableRVA;
					if(offset < name_table)
						_text.ImportAddressTable.NameTableRVA = name_table+diff;
				}

				if(_text.ImportLookupTable != null)
				{
					int name_table = _text.ImportLookupTable.NameTableRVA;
					if(offset < name_table)
						_text.ImportLookupTable.NameTableRVA = name_table+diff;
					
				}
				if(_text.NameTable != null)
				{
					short hint = _text.NameTable.Hint;
					if(offset < hint)
						_text.NameTable.Hint = (short)(hint+((short)diff));
				}
			}
		}

		private void MoveBlobReferences(int off,int diff)
		{
			//check stream tables for blob reference
			FieldTable f = (FieldTable)_text.PoundTildaStream.Tables[StreamTable.FIELD_TABLE];
			FieldTableRow fr;
			int i,offset,count;
			if(f != null)
			{
				count = f.Count;
				for(i = 0;i < count;i++)
				{
					fr = f.Get(i);
					offset = fr.Signature;
					if(off < offset)
					{
						fr.Signature = offset+diff;
					}
				}
			}

			MethodDefTable md = (MethodDefTable)_text.PoundTildaStream.Tables[StreamTable.METHODDEF_TABLE];
			MethodDefTableRow mdr;
			if(md != null)
			{
				count = md.Count;
				for(i = 0;i < count;i++)
				{
					mdr = md.Get(i);
					offset = mdr.Signature;
					if(off < offset)
						mdr.Signature = offset+diff;
				}
			}

			MemberRefTable mr = (MemberRefTable)_text.PoundTildaStream.Tables[StreamTable.MEMBERREF_TABLE];
			MemberRefTableRow mrr;
			if(mr != null)
			{
				count = mr.Count;
				for(i = 0;i < count;i++)
				{
					mrr = mr.Get(i);
					offset = mrr.Signature;
					if(off < offset)
						mrr.Signature = offset+diff;
				}
			}

			ConstantTable c = (ConstantTable)_text.PoundTildaStream.Tables[StreamTable.CONSTANT_TABLE];
			ConstantTableRow cr;
			if(c != null)
			{
				count = c.Count;
				for(i = 0;i < count;i++)
				{
					cr = c.Get(i);
					offset = cr.Value;
					if(off < offset)
						cr.Value = offset+diff;
				}
			}

			CustumAttributeTable ca = (CustumAttributeTable)_text.PoundTildaStream.Tables[StreamTable.CUSTUMATTRIBUTE_TABLE];
			CustumAttributeTableRow car;
			if(ca != null)
			{
				count = ca.Count;
				for(i = 0;i < count;i++)
				{
					car = ca.Get(i);
					offset = car.Value;
					if(off < offset)
						car.Value = offset+diff;
				}
			}

			FieldMarshalTable fm = (FieldMarshalTable)_text.PoundTildaStream.Tables[StreamTable.FIELDMARSHAL_TABLE];
			FieldMarshalTableRow fmr;
			if(fm != null)
			{
				count = fm.Count;
				for(i = 0;i < count;i++)
				{
					fmr = fm.Get(i);
					offset = fmr.NativeType;
					if(off < offset)
						fmr.NativeType = offset+diff;
				}
			}

			DeclSecurityTable dc = (DeclSecurityTable)_text.PoundTildaStream.Tables[StreamTable.DECLSECURITY_TABLE];
			DeclSecurityTableRow dcr;
			if(dc != null)
			{
				count = dc.Count;
				for(i = 0;i < count;i++)
				{
					dcr = dc.Get(i);
					offset = dcr.PermissionSet;
					if(off < offset)
						dcr.PermissionSet = offset+diff;
				}
			}

			StandAloneSigTable sas = (StandAloneSigTable)_text.PoundTildaStream.Tables[StreamTable.STANDALONESIG_TABLE];
			StandAloneSigTableRow sasr;
			if(sas != null)
			{
				count = sas.Count;
				for(i = 0;i < count;i++)
				{
					sasr = sas.Get(i);
					offset = sasr.Signature;
					if(off < offset)
						sasr.Signature = offset+diff;
				}
			}

			PropertyTable p = (PropertyTable)_text.PoundTildaStream.Tables[StreamTable.PROPERTY_TABLE];
			PropertyTableRow pr;
			if(p != null)
			{
				count = p.Count;
				for(i = 0;i < count;i++)
				{
					pr = p.Get(i);
					offset = pr.Type;
					if(off < offset)
						pr.Type = offset+diff;
				}
			}

			TypeSpecTable ts = (TypeSpecTable)_text.PoundTildaStream.Tables[StreamTable.TYPESPEC_TABLE];
			TypeSpecTableRow tsr;
			if(ts != null)
			{
				count = ts.Count;
				for(i = 0;i < count;i++)
				{
					tsr = ts.Get(i);
					offset = tsr.Signature;
					if(off < offset)
						tsr.Signature = offset+diff;
				}
			}

			AssemblyTable a = (AssemblyTable)_text.PoundTildaStream.Tables[StreamTable.ASSEMBLY_TABLE];
			AssemblyTableRow ar;
			if(a != null)
			{
				count = a.Count;
				for(i = 0;i < count;i++)
				{
					ar = a.Get(i);
					offset = ar.PublicKey;
					if(off < offset)
						ar.PublicKey = offset+diff;
				}
			}

			AssemblyRefTable ar2 = (AssemblyRefTable)_text.PoundTildaStream.Tables[StreamTable.ASSEMBLYREF_TABLE];
			AssemblyRefTableRow arr;
			if(ar2 != null)
			{
				count = ar2.Count;
				for(i = 0;i < count;i++)
				{
					arr = ar2.Get(i);
					offset = arr.PublicKeyOrToken;
					if(off < offset)
						arr.PublicKeyOrToken = offset+diff;
					offset = arr.HashValue;
					if(off < offset)
						arr.HashValue = offset+diff;
				}
			}

			FileTable f2 = (FileTable)_text.PoundTildaStream.Tables[StreamTable.FILE_TABLE];
			FileTableRow fr2;
			if(f2 != null)
			{
				count = f2.Count;
				for(i = 0;i < count;i++)
				{
					fr2 = f2.Get(i);
					offset = fr2.HashValue;
					if(off < offset)
						fr2.HashValue = offset+diff;
				}
			}
			
			MethodSpecTable ms = (MethodSpecTable)_text.PoundTildaStream.Tables[StreamTable.METHODSPEC_TABLE];
			MethodSpecTableRow ms2;
			if(ms != null)
			{
				count = ms.Count;
				for(i = 0;i < count;i++)
				{
					ms2 = ms.Get(i);
					offset = ms2.Instantiation;
					if(off < offset)
						ms2.Instantiation = offset+diff;
				}
			}
		}

		//Assembly
		public int GetCodeSize()
		{
			List<ClassDescriptor> cd = GetInternalClasses();
			int i,cd_count = cd.Count;
			int size = 0;
			for(i = 0;i < cd_count;i++)
				size += GetClassesCodeSize(cd[i]);
			return size;
		}

		public int GetInstructionCount()
		{
			List<ClassDescriptor> cd = GetInternalClasses();
			int i,cd_count = cd.Count;
			int count = 0;
			for(i = 0;i < cd_count;i++)
				count += GetClassesInstructionCount(cd[i]);
			return count;
		}

		private void MoveStreamHeaders(int off,int diff)
		{
			StreamHeaders shs = _text.StreamHeaders;
			int count = shs.Count;
			int i;
			for(i = 0;i < count;i++)
			{
				if(shs[i].Offset > off)
					shs[i].Offset += diff;
			}
		}

		public Token GetEntryPointToken()
		{
			return _text.CLIHeader.EntryPointToken;
		}

		//Class
		public List<ClassDescriptor> GetInternalClasses()
		{
			List<ClassDescriptor> cd = new List<ClassDescriptor>();

			StringsStream strings = _text.StringsStream;
			TypeDefTable td = (TypeDefTable)_text.PoundTildaStream.Tables[StreamTable.TYPEDEF_TABLE];
			TypeDefTableRow row;
			int i,count = td.Count;
			String name;
			Token token;
			TypeDefClassDescriptor class_descriptor;
			byte [] name_bytes;
			for(i = 0;i < count;i++)
			{
				row = td.Get(i);
				name_bytes = strings.Get(row.Name);
				if(name_bytes != null)
				{
					name = ASCIIEncoding.ASCII.GetString(name_bytes);
					//strip off null on the end
					name = name.Substring(0,name.Length-1);
					if(!name.Equals("<Module>"))
					{
						token = new Token(StreamTable.TYPEDEF_TABLE,i+1);
						class_descriptor = new TypeDefClassDescriptor(this,BlobElementType.ELEMENT_TYPE_CLASS,token);
						//TODO: Set everwhere that returns new ClassDescriptors
						_typedef_update_tokens += new EventHandler(class_descriptor.Update);
						cd.Add((ClassDescriptor)class_descriptor);
					}
				}
			}
	
			return cd;
		}

		public ClassDescriptor GetMethodsClassDescriptor(Token token)
		{
			if(token.Table == StreamTable.METHODDEF_TABLE)
			{
				int row = token.Row;
				if(row > 0)
				{
					TypeDefTable td = (TypeDefTable)_text.PoundTildaStream.Tables[StreamTable.TYPEDEF_TABLE];
					TypeDefTableRow r;
					int i,count = td.Count;
					int ret = count-1;
					for(i = 0;i < count;i++)
					{
						r = td.Get(i);
						if(r.MethodList > row && i > 0)
						{
							ret = i-1;
						}
					}
					Token t = new Token(StreamTable.TYPEDEF_TABLE,ret);
					return (ClassDescriptor)new TypeDefClassDescriptor(this,BlobElementType.ELEMENT_TYPE_CLASS,t);
				}
			}
			return null;
		}

		public List<ClassDescriptor> GetExternalClasses()
		{
			//TYPEREF
			return null;


			//EXPORTEDTYPE????
		}

		public int GetClassesCodeSize(ClassDescriptor cd)
		{
			if(cd != null)
			{
				if(cd.Type == ClassDescriptor.TYPEDEF_CLASSDESCRIPTOR)
				{
					List<MethodDescriptor> md = GetMethodDescriptorsForClass(((TypeDefClassDescriptor)cd).ClassToken);
					int i,md_count = md.Count;
					int size = 0;
					for(i = 0;i < md_count;i++)
						size += GetMethodsCodeSize(md[i]);
					return size;
				}
			}
			return 0;
		}

		public int GetClassesInstructionCount(ClassDescriptor cd)
		{
			if(cd != null)
			{
				if(cd.Type == ClassDescriptor.TYPEDEF_CLASSDESCRIPTOR)
				{
					List<MethodDescriptor> md = GetMethodDescriptorsForClass(((TypeDefClassDescriptor)cd).ClassToken);
					int i,md_count = md.Count;
					int count = 0;
					for(i = 0;i < md_count;i++)
						count += GetMethodsInstructionCount(md[i]);
					return count;
				}
			}
			return 0;
		}

		//Method
		public List<MethodDescriptor> GetMethodDescriptorsForClass(Token token)
		{
			if(token.Table == StreamTable.TYPEDEF_TABLE)
			{

				TypeDefTable td = (TypeDefTable)_text.PoundTildaStream.Tables[StreamTable.TYPEDEF_TABLE];
				int count = td.Count;
				int row = token.Row-1;
				if(row >= 0 && row < count)
				{
					TypeDefTableRow r;
					List<MethodDescriptor> ret = new List<MethodDescriptor>();
					r = td.Get(row);
					
					int first = r.MethodList-1;
					int last = 0;
					MethodDefTable md = (MethodDefTable)_text.PoundTildaStream.Tables[StreamTable.METHODDEF_TABLE];
					if(row < count-1)
					{
						r = td.Get(row+1);
						last = r.MethodList-2;
					}
					else
					{
						last = md.Count-1;
					}
					int i;
					Token t;
					for(i = first;i <= last;i++)
					{
						t = new Token(StreamTable.METHODDEF_TABLE,i+1);
						ret.Add(new MethodDescriptor(this,t));
					}
					return ret;
				}
				return null;
			}
			return null;
		}

		public List<CLELInstruction> GetCodeForMethod(Token token)
		{
			if(token != null)
			{
				MethodHeader mh = GetMethodHeader(token);
				if(mh != null && mh.Code != null)
				{
					return new List<CLELInstruction>(mh.Code);
				}
			}
			return null;
		}

		public String GetMethodsName(Token token)
		{
			if(token != null)
			{
				if(token.Table == StreamTable.METHODDEF_TABLE)
				{
					MethodDefTable md = (MethodDefTable)_text.PoundTildaStream.Tables[StreamTable.METHODDEF_TABLE];
					int md_count = md.Count;
					int row = token.Row;
					if(row > 0 && row <= md_count)
					{
						MethodDefTableRow mdtr = md.Get(row-1);
						int name = mdtr.Name;
						byte [] name_bytes = _text.StringsStream.Get(name);
						ASCIIEncoding encoding = new ASCIIEncoding();
						return encoding.GetString(name_bytes);
					}
				}
			}
			return "";
		}

		public MethodLocalsBlobInfo GetMethodsLocals(Token token)
		{
			if(token != null)
			{
				if(token.Table == StreamTable.METHODDEF_TABLE)
				{
					MethodDefTable md = (MethodDefTable)_text.PoundTildaStream.Tables[StreamTable.METHODDEF_TABLE];
					int md_count = md.Count;
					int row = token.Row;
					if(row > 0 && row <= md_count)
					{
						MethodDefTableRow mdtr = md.Get(row-1);
						MethodHeader mh = mdtr.MethodHeader;
						if(mh != null)
						{
							int local_token = mh.LocalVarSigToken;
							Token temp = new Token(local_token);
							if(temp.Row == 0)
							{
								//no locals return empty MethodLocalsBlobInfo
								return new MethodLocalsBlobInfo(null,this);
							}
							StandAloneSigTable st = (StandAloneSigTable)_text.PoundTildaStream.Tables[StreamTable.STANDALONESIG_TABLE];
							if(temp.Row > 0 && temp.Row <= st.Count)
							{
								StandAloneSigTableRow r = st.Get(temp.Row-1);
								return GetMethodsLocals(GetBlobFromHeap(r.Signature));
							}
						}
					}
				}
			}
			return null;
		}

		public void SetMethodsCode(MethodDescriptor md,List<CLELInstruction> code,MethodLocalsBlobInfo locals)
		{
			if(code == null)
				throw new ArgumentException("Code cannot be null");
			if(md == null)
				throw new ArgumentException("Method Descriptor cannot be null");
			Token method_token = md.MethodToken;
			MethodHeader mh = GetMethodHeader(method_token);
			bool is_tiny;
			if(mh != null)
			{
				byte [] bytes = mh.GetBytes(true);
				int prev_size = bytes.Length;

				is_tiny = mh.IsTiny();

				mh.Code = new List<CLELInstruction>(code);
				
				int locals_count = 0;
				List<ClassDescriptor> l = null;
				if(locals != null)
				{
					l = locals.Locals;
					if(l != null)
						locals_count = l.Count;
				}

				bytes = mh.GetBytes(true);
				int after_size = bytes.Length;
				int diff = after_size - prev_size;
				diff = Bits.AlignToFourByteBoundry(diff);
				
				int method_rva = 0;
				if(diff != 0)
				{
					MethodDefTable mdt = (MethodDefTable)_text.PoundTildaStream.Tables[StreamTable.METHODDEF_TABLE];
					MethodDefTableRow mdtr = mdt.Get(md.MethodToken.Row-1);
					method_rva = mdtr.RVA;
					MoveTextSections(method_rva,diff);
				}

				int prev_local_var_sig_token = mh.LocalVarSigToken;
				int blob_rva = _text.CLIHeader.Metadata.VirtualAddress + _text.StreamHeaders.GetStreamHeader(StreamHeader.BLOB_NAME).Offset;
				byte [] local_bytes;
				Token t;
				StandAloneSigTable sast;
				if(prev_local_var_sig_token == 0 && locals_count > 0)
				{
					//compenstate for switch from tiny to fat
					if(is_tiny)
						MoveTextSections(method_rva,Bits.AlignToFourByteBoundry(MethodHeader.METHODHEADER_FAT_HEADER_SIZE - MethodHeader.METHODHEADER_SMALL_HEADER_SIZE));

					//no locals -> locals
					//add locals to blob
					local_bytes = locals.MethodLocalsToBytes();
					int add_offset = _text.BlobStream.Add(new Blob(local_bytes));
					//move stream headers after blob
					//because of the blob value that was added
					StreamHeader sh = _text.StreamHeaders.GetStreamHeader(StreamHeader.BLOB_NAME);
					sh.Size = sh.Size + local_bytes.Length;
					MoveStreamHeaders(sh.Offset,local_bytes.Length);
					
					//move everything that points after blob
					MoveTextSections(blob_rva,local_bytes.Length);

					//add row to StandAloneSigTable
					StandAloneSigTableRow row = new StandAloneSigTableRow(add_offset);
					sast = (StandAloneSigTable)_text.PoundTildaStream.Tables[StreamTable.STANDALONESIG_TABLE];
					sast.Add(row);
					t = new Token(StreamTable.STANDALONESIG_TABLE,sast.Count);
					
					_text.PoundTildaStream.TableRows[StreamTable.STANDALONESIG_TABLE]++;

					//set localvarsigtoken in method header
					mh.LocalVarSigToken = t.GetEncodedToken();	
				
					//move everything that points after stand alone sig table	
					sh = _text.StreamHeaders.GetStreamHeader(StreamHeader.TILDA_NAME);
					sh.Size = sh.Size + local_bytes.Length;
					MoveStreamHeaders(sh.Offset,2);
					
					//MoveTextSections(sh.Offset,4);
				}
				else if(prev_local_var_sig_token != 0 && locals_count > 0)
				{
					//locals -> locals
					t = new Token(prev_local_var_sig_token);
					int row = t.Row;
					sast = (StandAloneSigTable)_text.PoundTildaStream.Tables[StreamTable.STANDALONESIG_TABLE];
					StandAloneSigTableRow sastr = sast.Get(row-1);
					int blob_offset = sastr.Signature;
			
					//convert locals into bytes
					local_bytes = locals.MethodLocalsToBytes();
					//for(int k = 0;k < local_bytes.Length;k++)
					//	Console.Write(local_bytes[k]+" ");
					//Console.WriteLine("\n");
					int blob_old_len = _text.BlobStream.Resize(blob_offset,local_bytes.Length);
					//replace locals in blob
					_text.BlobStream.Set(blob_offset,local_bytes);

					//move what points to blob blob_diff after blob_offset
					int blob_diff = local_bytes.Length - blob_old_len;
					StreamHeader sh = _text.StreamHeaders.GetStreamHeader(StreamHeader.BLOB_NAME);
					sh.Size = sh.Size + blob_diff;
					MoveStreamHeaders(sh.Offset,blob_diff);

					MoveBlobReferences(blob_offset,blob_diff);

					//move everything that points after blob
					MoveTextSections(blob_rva,blob_diff);
				}
				else if(prev_local_var_sig_token != 0 && locals_count == 0)
				{
					//locals -> no locals
					//remove blob
					//set local var sig token to 0
					//move everything that points after blob/text
					//remove LocalVarSig row
					//update local var sig tokens in other method headers
					//move everything that points after blob/text
				}
			}
		}

		public void SetMethodsSEHDataSection(Token token,MethodHeaderDataSection seh)
		{
			if(token != null)
			{
				MethodHeader mh = GetMethodHeader(token);
				if(mh != null)
				{
					mh.SetSEHDataSection(seh);
				}
			}
		}

		public MethodHeaderDataSection GetMethodsSEHDataSection(Token token)
		{
			if(token != null)
			{
				MethodHeader mh = GetMethodHeader(token);
				if(mh != null)
				{
					return mh.GetSEHDataSection();
				}
			}
			return null;
		}

		public int GetMethodsCodeSize(MethodDescriptor md)
		{
			if(md != null)
			{
				MethodHeader mh = GetMethodHeader(md.MethodToken);
				if(mh != null)
				{
					List<CLELInstruction> code = mh.Code;
					if(code != null)
					{
						int i,code_count = code.Count;
						int size = 0;
						for(i = 0;i < code_count;i++)
							size += code[i].Length;
						return size;
					}
				}
			}
			return 0;
		}

		public int GetMethodsInstructionCount(MethodDescriptor md)
		{
			if(md != null)
			{
				MethodHeader mh = GetMethodHeader(md.MethodToken);
				if(mh != null)
				{
					List<CLELInstruction> code = mh.Code;
					if(code != null)
					{
						return code.Count;
					}
				}
			}
			return 0;
		}

		public MethodDescriptor GetMethodDescriptor(Token token)
		{
			if(token == null)
				throw new ArgumentException("Method token cannot be null");
			if(token.Table == StreamTable.METHODDEF_TABLE)
			{
				MethodDefTable md = (MethodDefTable)_text.PoundTildaStream.Tables[StreamTable.METHODDEF_TABLE];
				MethodDefTableRow md_r = md.Get(token.Row-1);
				if(md_r != null)
				{
					return new MethodDescriptor(this,token);
				}
			}
			return null;
		}

		public MethodDescriptor GetMainsMethodDescriptor()
		{
			int encoded_token = _text.CLIHeader.EntryPointToken.GetEncodedToken();
			if(encoded_token != 0)
			{
				Token token = new Token(encoded_token);
				if(token.Table == StreamTable.METHODDEF_TABLE)
				{
					MethodDefTable md = (MethodDefTable)_text.PoundTildaStream.Tables[StreamTable.METHODDEF_TABLE];
					MethodDefTableRow md_r = md.Get(token.Row-1);
					if(md_r != null)
					{
						return new MethodDescriptor(this,token);
					}
				}
			}
			return null;
		}
				
		public MethodBlobInfo GetMethodBlobInfo(Token token)
		{
			if(token == null)
				throw new ArgumentException("Method token cannot be null");
			if(token.Table == StreamTable.METHODDEF_TABLE)
			{
				MethodDefTable md = (MethodDefTable)_text.PoundTildaStream.Tables[StreamTable.METHODDEF_TABLE];
				MethodDefTableRow md_r = md.Get(token.Row-1);
				BlobStream blob_stream = _text.BlobStream;
				byte [] m_params = blob_stream.GetBytes(md_r.Signature);
				if(m_params != null)
				{
					uint ordinal_number = 1;
					short flags = md_r.Flags;
					if((flags & MethodFlags.STATIC) == MethodFlags.STATIC)
					{
						ordinal_number = 0;
					}
					return new MethodBlobInfo(m_params,ordinal_number,this);
				}
			}
			return null;
		}

		public short GetMethodFlags(Token token)
		{
			if(token == null)
				throw new ArgumentException("Method token cannot be null");
			if(token.Table == StreamTable.METHODDEF_TABLE)
			{
				MethodDefTable md = (MethodDefTable)_text.PoundTildaStream.Tables[StreamTable.METHODDEF_TABLE];
				MethodDefTableRow md_r = md.Get(token.Row-1);
				if(md_r != null)
					return md_r.Flags;
				else
					throw new Exception("Method does not exist");
			}
			throw new Exception("Bad stream table type");
		}
	}
}
